/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.server.listener;

import io.iec.edp.caf.commons.core.SerializerFactory;
import io.iec.edp.caf.commons.core.enums.SerializeType;
import io.iec.edp.caf.logging.CommonConstant;
import io.iec.edp.caf.rpc.api.event.ExceptionRpcInvokeEventArgs;
import io.iec.edp.caf.rpc.api.event.IRpcClientEventListener;
import io.iec.edp.caf.rpc.api.event.PostRpcInvokeEventArgs;
import io.iec.edp.caf.rpc.api.event.PreRpcInvokeEventArgs;
import io.iec.edp.caf.rpc.api.support.ConstanceVarible;
import io.iec.edp.caf.rpc.api.utils.Validator;
import lombok.var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

public class RpcServerLoggingListener implements IRpcClientEventListener {

    private final String START_TIME = "startTime";
    private final Logger logger = LoggerFactory.getLogger(RpcServerLoggingListener.class);

    @Override
    //将ServiceUnitName放入MDC
    public void preInvokeEvent(PreRpcInvokeEventArgs args) {
        Map<String, Object> localContext = args.getLocalContext();
        Map<String, String> context = args.getContext();

        String msu = (String) localContext.get(CommonConstant.LOG_MSU_ID);
        MDC.put(CommonConstant.LOG_MSU_ID, msu);
        long start = System.currentTimeMillis();
        localContext.put(START_TIME, start);

        String serviceId = context.get(ConstanceVarible.CURRENT_SERVICE_ID);
        String origin = "true".equals(context.get(ConstanceVarible.IS_LOCAL)) ? "local" : "remote";

        var serializer = SerializerFactory.getSerializer(SerializeType.Json);
        if (logger.isInfoEnabled()) {
            logger.info("Start Rpc {} invoking: serviceId is {}, param is {}", origin, serviceId, serializer.serializeToString(args.getParameters()));
        }

    }

    @Override
    //记录服务端请求成功日志
    public void postInvokeEvent(PostRpcInvokeEventArgs args) {
        Map<String, Object> localContext = args.getLocalContext();
        Map<String, String> context = args.getContext();
        long end = System.currentTimeMillis();
        Long cost = end - (long) localContext.get(START_TIME);

        String serviceId = context.get("serviceId");
        String origin = "1".equals(context.get("local")) ? "local" : "remote";
        var serializer = SerializerFactory.getSerializer(SerializeType.Json);

        if (logger.isInfoEnabled()) {
            logger.info("Finish Rpc {} invoking: serviceId is {},cost {}ms, result is {}", origin, serviceId, cost, serializer.serializeToString(args.getMethodResult()));
        }
    }

    @Override
    //记录服务端请求异常日志
    public void exceptionInvokeEvent(ExceptionRpcInvokeEventArgs args) {
        Map<String, String> context = args.getContext();
        Exception exception = args.getException();

        String serviceId = context.get("serviceId");
        String origin = "1".equals(context.get("local")) ? "local" : "remote";

//        logger.error("Exception in Rpc {} invoking: serviceId is {},exception is {}", origin, serviceId, getExceptionToString(exception));
        logger.error("Exception in Rpc {} invoking: serviceId is {},exception is {}", origin, serviceId, getExceptionToString(exception));
    }

    public String getExceptionToString(Throwable e) {
        if (e == null){
            return "";
        }
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();//replaceAll("\r\n","").replaceAll("\n","");
    }
}

